package com.zjpavt.client.page;

import com.zjpavt.client.Client;
import com.zjpavt.client.hal.ArtNetConfig;
import com.zjpavt.client.hal.LedScreen;
import com.zjpavt.client.page.abstractpage.AbstractBasePage;
import com.zjpavt.client.page.basepage.BaseEditablePage;
import com.zjpavt.client.page.basepage.BaseSonPage;
import com.zjpavt.client.page.editableunit.EditUnit;
import com.zjpavt.client.page.editableunit.EditUnitNum;
import com.zjpavt.client.page.editableunit.EditUnitString;
import com.zjpavt.client.page.intefacepage.EditablePage;
import com.zjpavt.client.page.intefacepage.ParentPage;
import com.zjpavt.client.page.intefacepage.SonPage;
import com.zjpavt.client.page.pageunit.ScreenLine;
import com.zjpavt.client.util.LoggerUtil;
import com.zjpavt.client.util.NumberUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * dmx 参数设置
 * @author zyc
 */
@Slf4j
public class DmxParameterPage extends AbstractBasePage implements SonPage, EditablePage {
    private static final String TYPE = "type:";
    private static final String SPEED = "speed:";
    private static final String EXTERNSTART = "yu:";
    private static final String BEGIN_CHANNEL_INDEX = "begin:";
    private static final String CHANNEL_INDEX = "length:";

    /**
     * type:         15
     * speed:10  yu:255
     * begin:500
     * length:12
     * @param pageNum
     */

    public DmxParameterPage(int pageNum, ParentPage parentPage,long mRefreshPeriod) {
        super(pageNum,mRefreshPeriod);
        this.sonPage = new BaseSonPage(pageNum,parentPage,0,this);
        this.editablePage = new BaseEditablePage(pageNum,0,this);
    }


    private BaseSonPage sonPage;
    /***
     * 可编辑对象
     * @return
     */
    private BaseEditablePage editablePage;

    /**
     * 获取当前编辑状态下的实时数据
     * 未保存 可能已经修改
     * @return
     */
    private String getType() {
        return getEditUnit(0).getText();
    }
    private int getSpeed() {
        return (Integer) getEditUnit(1).getValue();
    }
    private int getExternstart() {
        return (Integer) getEditUnit(2).getValue();
    }
    private int getBeginChannelIndex() {
        return (Integer) getEditUnit(3).getValue();
    }
    private int getChannelIndex() {
        return (Integer) getEditUnit(4).getValue();
    }

    @Override
    public void refreshPage() {
        List<ScreenLine> result = new ArrayList<>();
        result.add(new ScreenLine.ScreenLineBuilder().text(TYPE + getType()).pageNum(getPageNum()).build());
        String line2 = SPEED + NumberUtil.getFormat00(getSpeed()) + " "
                       + EXTERNSTART + NumberUtil.getFormat000(getExternstart());
        result.add(new ScreenLine.ScreenLineBuilder().text(line2).build());
        String line3 = BEGIN_CHANNEL_INDEX + NumberUtil.getFormat000(getBeginChannelIndex());
        result.add(new ScreenLine.ScreenLineBuilder().text(line3).build());
        String line4 = CHANNEL_INDEX + NumberUtil.getFormat000(getChannelIndex());
        result.add(new ScreenLine.ScreenLineBuilder().text(line4).build());
        LedScreen.getInstance().setText(result);
    }

    @Override
    public ParentPage getParentPage() {
        return sonPage.getParentPage();
    }

    @Override
    public AbstractBasePage setParentPage(ParentPage parentPage) {
        sonPage.setParentPage(parentPage);
        return this;
    }

    @Override
    public void enterSonPage() {
        refreshPage();
    }

    @Override
    public void exitSonPage() {
        if (isInEditMode()) {
            throw new IllegalArgumentException();
        }
        sonPage.exitSonPage();
    }

    @Override
    public void onKeyDown() {
        if (isInEditMode()) {
            editablePage.onKeyDown();
        } else {
            super.onKeyDown();
        }
    }

    @Override
    public void onKeyUp() {
        if (isInEditMode()) {
            editablePage.onKeyUp();
        } else {
            super.onKeyUp();
        }
    }

    @Override
    public void onKeySet() {
        if (isInEditMode()) {
            editablePage.onKeySet();
        } else {
            enterEditMode();
        }
    }

    /**
     * 在编辑模式下 确认时 退出编辑模式
     * 如果不在编辑下 退出当前的页面
     *
     */
    @Override
    public void onKeyEnt() {
        if (isInEditMode()) {
            exitEditMode();
        } else {
            exitSonPage();
        }
    }

    /*********************************************************
    * 可编辑页面的方法
    * */

    @Override
    public void addEditUnit(EditUnit e) {
        editablePage.addEditUnit(e);
    }

    @Override
    public void removeEditUnit(EditUnit e) {
        editablePage.removeEditUnit(e);
    }

    @Override
    public void clearEditUnit() {
        editablePage.clearEditUnit();
    }

    @Override
    public EditUnit getEditUnit(int index) {
        return editablePage.getEditUnit(index);
    }

    @Override
    public int getCurrBlinkIndex() {
        return editablePage.getCurrBlinkIndex();
    }

    @Override
    public void exitEditMode() {
        editablePage.exitEditMode();
        startAutoRefreshing();
    }

    @Override
    public boolean isInEditMode() {
        return editablePage.isInEditMode();
    }

    @Override
    public int getEditUnitSize() {
        return editablePage.getEditUnitSize();
    }

    @Override
    public void enterEditMode() {
        this.editablePage.enterEditMode();
        cancelAutoRefreshing();
    }

    @Override
    public void saveVal() {
        ScheduledFuture future = Client.mainThreadPool.schedule(()-> {
            try {
                ArtNetConfig.saveValue(getType(), getSpeed(), getExternstart(), getBeginChannelIndex(), getChannelIndex());
            } catch (Exception e) {
                log.error(LoggerUtil.convertException2String(e));
            }
        },0,TimeUnit.MILLISECONDS);
        try {
//          保持切换流畅 如果线程阻塞也能按时返回 并中断线程（timeout中）
            future.get(100, TimeUnit.MILLISECONDS);
        } catch (ExecutionException|InterruptedException e) {
            log.error(LoggerUtil.convertException2String(e));
        } catch (TimeoutException e) {
            log.error("save value timeout");
            future.cancel(true);
        }
        setDefaultVal();
    }

    @Override
    public void initEditUnits() {
        clearEditUnit();
//        type
        addEditUnit(new EditUnitString(1, 6, 11, ArtNetConfig.getTypeArray(),0));
//        speed
        addEditUnit(new EditUnitNum(2, 7, 8, 1,40,1));
//        域
        addEditUnit(new EditUnitNum(2, 13, 15,0,255,1));
//        beginIndex
        addEditUnit(new EditUnitNum(3, 7, 9,0,511,1));
//        length
        addEditUnit(new EditUnitNum(4, 8, 10,0,512,1));
        setDefaultVal();
    }

    @Override
    public void setDefaultVal() {
        getEditUnit(0).setCurrentVal(ArtNetConfig.getTypeIndex());
        getEditUnit(1).setCurrentVal(ArtNetConfig.getSpeed());
        getEditUnit(2).setCurrentVal(ArtNetConfig.getExternstart());
        getEditUnit(3).setCurrentVal(ArtNetConfig.getBeginChannelIndex());
        getEditUnit(4).setCurrentVal(ArtNetConfig.getChannelLength());
    }

    @Override
    public void close() {
    }

    @Override
    public void init() {
        initEditUnits();
    }
}
